package com.mytime.database;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;

import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;

import org.json.JSONException;
import org.json.JSONObject;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.Text;
import com.mytime.util.Functions;

@PersistenceCapable
public class Event {
	
	@PrimaryKey
	@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
	private Key key;
	
	@Persistent
	private String strKey;

	@Persistent
	private String encodedKey;

	@Persistent
	private String name;

	@Persistent
	private Text description;

	@Persistent
	private double cost;
	
	@Persistent
	private Date startDate;
	
	@Persistent
	private Date endDate;

	@Persistent 
	private HashSet<Key> venuesList = new HashSet<Key>();
	
	@Persistent 
	private HashSet<Timetable> eventTimes = new HashSet<Timetable>();

	@Persistent
	private String category;
	
	//*************//
	//Constructors//
	//***********//
	public Event() {
		
	}
	
	public Event(JSONObject data) {
		try {
			if (data.has("name") && data.getString("name") != null) {
				name = data.getString("name");
				key = KeyFactory.createKey(Event.class.getSimpleName(), name);
				encodedKey = KeyFactory.keyToString(key);
				strKey = Functions.removeSpecialCharacters(name).toLowerCase().replaceAll(" ", "_");
			}
			
			if (data.has("description") && data.getString("description") != null)
				setDescription(data.getString("description"));
			if (data.has("cost"))
				cost = data.getDouble("cost");
			if (data.has("startDate") && data.get("startDate") != null)
				setStartDate(data.getString("startDate"));
			if (data.has("endDate") && data.get("endDate") != null)
				setEndDate(data.getString("endDate"));
			if (data.has("category") && data.getString("category") != null)
				category = data.getString("category");

		} catch (JSONException e) {
			e.printStackTrace();
		}
	}
	
	//***************//
	//Public Methods//
	//*************//

	public void updateValues(JSONObject data) {
		
		try {
			if (data.has("description") && data.getString("description") != null)
				setDescription(data.getString("description"));
			if (data.has("cost"))
				cost = data.getDouble("cost");
			if (data.has("startDate") && data.get("startDate") != null)
				setStartDate(data.getString("startDate"));
			if (data.has("endDate") && data.get("endDate") != null)
				setEndDate(data.getString("endDate"));
			if (data.has("category") && data.getString("category") != null)
				category = data.getString("category");

		} catch (JSONException e) {
			e.printStackTrace();
		}
		
	}

	public Key getKey() {
		return key;
	}
	
	public void setKey(Key key) {
		this.key = key;
	}
		
	public String getEncodedKey() {
		return encodedKey;
	}

	public void setEncodedKey(String encodedKey) {
		this.encodedKey = encodedKey;
	}

	public String getStrKey() {
		return strKey;
	}

	public void setStrKey(String strKey) {
		this.strKey = strKey;
	}

	public String getName() {
		return name;
	}
	
	public void setName(String name) {
		this.name = name;
	}
	
	public String getDescription() {
		String value = this.description.getValue(); 
		return value;
	}

	public void setDescription(String description) {
		Text descriptionText = new Text(description);
		this.description = descriptionText;
	}

	public double getCost() {
		return cost;
	}
	
	public void setCost(double cost) {
		this.cost = cost;
	}

	public Date getStartDate() {
		return startDate;
	}
	
	public void setStartDate(String startDate) {
		DateFormat fmt = new SimpleDateFormat("dd/MM/yyyy");  
		
		//If user doesn't provide one, the start Date will be the current date 
		Date data = new java.util.Date(System.currentTimeMillis());
		
		try {
			if (startDate != null)
				data = new Date(fmt.parse(startDate).getTime());
			
		} catch (ParseException e) {
			e.printStackTrace();
		}
		
		this.startDate = data;
	}
	
	public Date getEndDate() {
		return endDate;
	}
	
	public void setEndDate(String endDate) {
		DateFormat fmt = new SimpleDateFormat("dd/MM/yyyy");
		
		//If user doesn't provide one, the end Date will be null 
		Date data = null;
		
		try {
			if (endDate != null)
				data = new Date(fmt.parse(endDate).getTime());
			
		} catch (ParseException e) {
			e.printStackTrace();
		}
		
		this.endDate = data;
	}
		
	public HashSet<Key> getVenuesList() {
		return venuesList;
	}

	public void setVenuesList(HashSet<Key> venuesList) {
		this.venuesList = venuesList;
	}

	public void addVenue(Key v) {
		venuesList.add(v);
	}

	public void removeVenue(Key v) {
		venuesList.remove(v);
	}

	public HashSet<Timetable> getEventTimes() {
		return eventTimes;
	}

	public void setEventTimes(HashSet<Timetable> eventTimes) {
		this.eventTimes = eventTimes;
	}

	public void addEventTime(Timetable entry) {
		this.eventTimes.add(entry);
	}

	public void removeEventTime(Timetable entry) {
		this.eventTimes.remove(entry);
	}

	public String getCategory() {
		return this.category;
	}

	public void setCategory(String category) {
		this.category = category;
	}

	public JSONObject toJSON() {
		JSONObject event = new JSONObject();
		
		AddIfNotNull(event, "eventKey", strKey);
		AddIfNotNull(event, "eventName", name);
		AddIfNotNull(event, "cost", cost);
		AddIfNotNull(event, "startDate", startDate);
		AddIfNotNull(event, "endDate", endDate);
		AddIfNotNull(event, "eventCategory", category);
		AddIfNotNull(event, "description", getDescription());
		
		return event;
	}

	private void AddIfNotNull(JSONObject j, String key, Object o) {
		try {
			if (o != null)
				j.put(key, o);
		} catch (JSONException e) {
			e.printStackTrace();
		}
	}
}